package pe.edu.upc.e41a.javasoft.daoImpl;

import java.util.List;
import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.TypedQuery;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import pe.edu.upc.e41a.javasoft.dao.PublicacionDao;
import pe.edu.upc.e41a.javasoft.domain.Publicacion;
import pe.edu.upc.e41a.javasoft.domain.Transaccion;

@Repository(value = "PublicacionDao")
public class PublicacionDaoImpl implements PublicacionDao {

	private static final Log log = LogFactory.getLog(PublicacionDaoImpl.class);

	@PersistenceContext
	transient EntityManager em;

	public final EntityManager entityManager() {
		EntityManager entityManager = em;
		if (entityManager == null)
			throw new IllegalStateException(
					"Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)");
		return entityManager;
	}	

	@Transactional
	@Override
	public void savePublicacion(Publicacion publicacion) {
		
		if (em == null)
			this.em = this.em;
		em.persist(publicacion);
		
	}

	@Transactional
	@Override
	public void updatePublicacion(Publicacion publicacion) {
		if (em == null)
			this.em = this.em;
		em.merge(publicacion);
		em.flush();
		
	}

	@Transactional
	@Override
	public void deletePublicacion(Publicacion publicacion) {
		
		if (em == null)
			this.em = this.em;
		if (em.contains(publicacion)) {
			em.remove(publicacion);
		} else {
			Publicacion attached = this.findPublicacion(publicacion.getCodigo());
			em.remove(attached);
		}
		
	}

	@Override
	public Publicacion findPublicacion(Integer codigo) {
		
		if (codigo == null) return null;
        return em.find(Publicacion.class, codigo);
	}

	@Override
	public TypedQuery<Publicacion> findPublicacionByTituloEquals(String titulo) {
		
	        if (titulo == null || titulo.length() == 0) throw new IllegalArgumentException("The titulo argument is required");
	        TypedQuery<Publicacion> q = em.createQuery("SELECT o FROM Publicacion AS o WHERE o.titulo = :titulo", Publicacion.class);
	        q.setParameter("titulo", titulo);
	        return q;
	}

	@Override
	public List<Publicacion> findAllPublicacion() {
		
		return em.createQuery("SELECT o FROM Publicacion o", Publicacion.class).getResultList();
	}
	
	@Override
	public TypedQuery<Publicacion> MostrarPublicacion(Integer IdPublicacion) {
		
		
		
		 TypedQuery<Publicacion> q = em.createQuery("SELECT o.codigo, o.titulo, o.precio,u.nombres,u.apellido_paterno, u.apellido_materno FROM Publicacion o "+
				 									//"inner join Usuario u on u.Codigo=o.Usuario" +
				 									"inner join Usuario u" +
				 									"WHERE o.codigo= :IdPublicacion", Publicacion.class);
	        q.setParameter("codigo", IdPublicacion);
	        return q;
	        
	        
	        
	}
	
	@Override
	public List<Publicacion> listarPublicacionPorTituloODescripcion(String cadena) {
		// TODO Auto-generated method stub
		return em.createQuery("SELECT o FROM Publicacion o where upper(o.titulo) like upper(:cadena) or upper(o.descripcion) like upper(:cadena)",Publicacion.class).setParameter("cadena",'%'+cadena+'%').getResultList();
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<Publicacion> listarPublicacionMasVisitadas() {
		List<Publicacion> mPublicacionList = null;
	   	
	   	StringBuilder mQuery = new StringBuilder();
	   	mQuery.append(" SELECT p FROM Publicacion p ");
	   	mQuery.append(" inner join p.visitas v ");
	   	mQuery.append(String.format(" WHERE p.estado = '%s' ",Publicacion.ESTADO_ACTIVO));
	   	mQuery.append(" GROUP BY p.codigo ");
	   	mQuery.append(" ORDER BY count(v.codigo) desc  ");
	   	mQuery.append(" LIMIT 5 ");
	   	
	   	mPublicacionList = (List<Publicacion>) entityManager().createQuery(mQuery.toString()).getResultList();
			return mPublicacionList;							
	}

	@Override
	@SuppressWarnings("unchecked")
	public List<Publicacion> listarPublicacionMasVendidas() {
		List<Publicacion> mPublicacionList = null;
	   	
	   	StringBuilder mQuery = new StringBuilder();
	   	mQuery.append(" SELECT p FROM Publicacion p ");
	   	mQuery.append(" inner join p.transaccions t ");
	   	mQuery.append(String.format(" WHERE p.estado = '%s' ",Publicacion.ESTADO_ACTIVO));
	   	mQuery.append(" GROUP BY p.codigo ");
	   	mQuery.append(" ORDER BY count(t.codigo) desc  ");
	   	mQuery.append(" LIMIT 5 ");
	   	
	   	mPublicacionList = (List<Publicacion>) entityManager().createQuery(mQuery.toString()).getResultList();
			return mPublicacionList;					
	}

	@Override
	public List<Publicacion> listarPublicacionPorUsuarioPorEstado(
			Integer usuario, Character estado) {
		TypedQuery<Publicacion> q = em
				.createQuery(
						"select p from Publicacion p " +
						"where p.usuario.codigo = :usuario and p.estado = :estado "
						,Publicacion.class);
		
		q.setParameter("usuario", usuario);
		q.setParameter("estado", estado);
		return q.getResultList();
	}

	@Override
	public  TypedQuery<Publicacion> findPublicacionsByTransaccions(List<Transaccion> transaccions) {
        if (transaccions == null) throw new IllegalArgumentException("The transaccions argument is required");
        StringBuilder queryBuilder = new StringBuilder("SELECT o FROM Publicacion AS o WHERE");
        for (int i = 0; i < transaccions.size(); i++) {
            if (i > 0) queryBuilder.append(" AND");
            queryBuilder.append(" :transaccions_item").append(i).append(" MEMBER OF o.transaccions");
        }
        TypedQuery<Publicacion> q = em.createQuery(queryBuilder.toString(), Publicacion.class);
        int transaccionsIndex = 0;
        for (Transaccion _transaccion: transaccions) {
            q.setParameter("transaccions_item" + transaccionsIndex++, _transaccion);
        }
        return q;
    }



	

}
